home *** CD-ROM | disk | FTP | other *** search
- Path: chronicle.mti.sgi.com!austern
- From: kuehl@uzwil.informatik.uni-konstanz.de (Dietmar Kuehl)
- Newsgroups: comp.std.c++
- Subject: Re: operators new[]/delete[]
- Date: 29 Feb 1996 09:14:42 PST
- Organization: FakultΣt fⁿr Mathematik und Informatik
- Approved: austern@isolde.mti.sgi.com
- Message-ID: <4h4agc$b1m@news.BelWue.DE>
- References: <313166CF.11C2@orbotech.co.il> <4gu414$62u@mulga.cs.mu.OZ.AU> <4h24c2$pq@caesar.ultra.net>
- Reply-To: dietmar.kuehl@uni-konstanz.de
- NNTP-Posting-Host: isolde.mti.sgi.com
- X-Original-Date: 29 Feb 1996 13:42:36 GMT
- X-Newsreader: TIN [version 1.2 PL2]
- X-Auth: PGPMoose V1.1 PGP comp.std.c++
- iQBVAwUBMTXfEEy4NqrwXLNJAQHRHAH/as7SoRd/95XaCs0i8eQNAYtXQd/KMr6p
- 1iSNVwpAkkJpP92slwmxiHc/KUh6qcyXI+C5ZiYvbS/3tulgEKEXig==
- =vxQ2
- Originator: austern@isolde.mti.sgi.com
-
- Hi,
-
- Pablo Halpern (phalpern@truffle.ultranet.com) wrote:
- : template <class T>
- : T* dup_array(const T* p, size_t s)
- : {
- : T *p2 = reinterpret_cast<T*> new char[s * sizeof(T)]; // note 1
-
- This is in no ways portable. However, it IS portable to allocate "raw"
- memory with 'operator new()' or 'operator new[]()'. See below...
- : }
-
- : void f(T* p, size_t s)
- : {
- : T* newp = dup_array(p, s);
- : // do something with newp
- : delete [] newp; // note 2
-
- This results indeed in undefined behavior.
- : }
-
- : I believe that something similar to the line marked "note 1" is common
- : practice for this sort of operation. However, I believe that the line
- : marked "note 2" is undefined behavior. Is there a way in the standard
- : can be modified so that the above code becomes well-defined and works as
- : intended? How does the STL deal with this in its "unitialized copy"
- : operation?
-
- There is no need to modify the standard because there is already a
- method available to deal with "raw" memory (see below), which e.g. use
- by STL.
-
- : There is another way to allocate raw memory, but here the operations are
- : even less defined (I believe):
-
- The operations are well defined, if used correctly...
-
- : void *p2 = operator new[] (s * sizeof(T));
- : delete p2; // What does this do? p2 was not the result of a normal
- : // new expression.
- : delete reinterpret_cast<T*> p2; // What does this do?
-
- Both attempts to release the memory pointed to by 'p2' result in
- undefined behavior: 'delete' can only be applied to objects allocated
- with 'new T' (for some type 'T'). Likewise, 'delete[]' can only release
- array objects allocated with 'new T[i]' (for some type 'T' and some
- value 'i'). The whole trick is to distinguish 'new T' from 'operator
- new()' and 'delete ptr' from 'operator delete()' (and correspondingly
- the array variants): They are just different operations (see e.g.
- "More Effective C++", S.Meyers, Addison-Wesly, Item 8).
-
- I will describe the stuff for arrays because apparently the "renew"
- topic is currently "in" :-) 'new T[i]' does something like:
-
- #include <new>
-
- T *new_T_array(size_t size) // a "homegrown" 'new T[size]'
- {
- // Allocate enough memory to hold the requested array plus
- // additional information about the size of the array. This
- // is as written NOT portable (insufficient alignment) but it
- // is also not necessary to do the non-portable stuff, if the
- // operations are encapsulated in an array class like 'vector':
- // the size can be stored somewhere else.
-
- void *ptr = operator new[](sizeof(T) + sizeof(size_t));
- size_t *sptr = static_cast<size_t*>(ptr);
- *sptr = size; // first store the size
- // .. then get the address of the actual array
- T *Tptr = static_cast<T*>(static_cast<void*>(sptr + 1));
-
- // now initialize the array
- for (size_t idx = 0; i < size; ++i)
- operator new(Tptr + idx) T();
- return Tptr;
- }
-
- However, this is NOT how it is indeed implemented but it depicts what
- is basically going on and how it COULD be implemented (well, not
- really: It is also necessary to take care of exceptions in the
- constructors and to release constructed objects if there is an
- exception). In particular, it shows the basics how to implement an own
- routine to allocate an array which basically feels like a built-in
- array (i.e. how 'operator new[]()' and "placement new" are used to
- create and initialize the array). Unfortunately, you cannot 'delete[]'
- an array created with 'new_T_array()'. Instead, you have to mimic the
- behavior of 'delete[]' using explicit destruction and 'operator
- delete[]()'. Here are the details:
-
- void delete_T_array(T *Tptr)
- {
- // Again this code is somewhat non-portable but againn this doesn't
- // matter because an array class can do a better (and portable) job
- // by storing the size somewhere else.
-
- // First retrieve the size from where it was store in 'new_T_array()':
- size_t *sptr = static_cast<size_t*>(static_cast<void*>(Tptr)) - 1;
- // ... then release the individual objects in the reverse order
- // constructed:
- for (size_t idx = *sptr; idx-- > 0; )
- Tptr[idx].~T();
-
- // Finally release the allocated "raw" memory
- operator delete[](static_cast<void*>(sptr));
- }
-
- Again, this is basically how it works (but e.g. with exception handling
- excluded). If you need to do similar stuff, you can do es like this.
- However, you should place such stuff in a class (e.g. because it is
- much simpler to do this portable). If do so, you are likely to end up
- with a class similar to 'vector'. So, why bother...?
-
- Concerning the 'renew' problematic: Using a combination of the stuff in
- 'new_T_array()' and 'delete_T_array()' you can implement a
- 'renew_T_array()' which is capable to 'renew' arrays allocated with
- 'new_T_array()' (or, even easier, if used with in a class to 'renew'
- the internal storage used to represent the array). However, there is
- still a minor inefficiency in comparison with 'realloc()': The need to
- store the size. Since the memory management almost certainly "knows"
- the size of the memory object somehow (I guess in all implementation it
- does know the size but I can also imagine that there could be a strange
- environment where this is not the case...), the number of elements in
- the memory object could potentially be deduced from this size. There is
- no portable method to do so. But I believe that this additional
- 'size_t' is not that heavy-weight to be a real problem which justifies
- some very specific language extension.
-
- : How do we solve these problems in a standard-conforming way. Does there
- : need to be special language for char arrays or void * allocations. (Or
- : is there already? I haven't found it.)
-
- How to solve this problems in a standard-conforming way: See above.
- ... and no, neither are there special allocations for 'char' arrays or
- 'void*', nor are they needed.
- --
- dietmar.kuehl@uni-konstanz.de
- http://www.informatik.uni-konstanz.de/~kuehl
- I am a realistic optimist - that's why I appear to be slightly pessimistic
- ---
- [ comp.std.c++ is moderated. To submit articles: Try just posting with your
- newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
- comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
- Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
- Comments? mailto:std-c++-request@ncar.ucar.edu
- ]
-